﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace DNA.Mvc.Installation.Installers
{
    /// <summary>
    /// ConfiguationNodeInstaller can add/remove/update config nodes for the *.config file(s) at package install progress.
    /// </summary>
    /// <remarks>You can set the name attribute to "Config" of the installer element to using this installer.</remarks>
    public class ConfigurationNodeInstaller : InstallerBase
    {
        public override string Name
        {
            get { return "config"; }
        }

        public override void Execute(InstallationContext context)
        {
            context.Trace.Warn("This installer will update your web.config file.");

            var config = GetConfig<ConfigurationNodeConfig>();
            string configPath = context.HttpContext.Server.MapPath("~/" + (String.IsNullOrEmpty(config.ConfigurationFile) ? "web.config" : config.ConfigurationFile));
            XmlDocument configDoc = new XmlDocument();
            configDoc.Load(configPath);
            
            if (configDoc == null)
                throw new Exception("The configuation file not found.");

            var _changed = false;

            foreach (var node in config.Nodes)
            {
                var xpath = node.Path;

                ConfiguationUpdateActions action = (ConfiguationUpdateActions)Enum.Parse(typeof(ConfiguationUpdateActions), node.Action);

                if (action == ConfiguationUpdateActions.Replace)
                {
                    XmlNode sectionNode = configDoc.SelectSingleNode(node.Path);
                    if (sectionNode != null)
                    {
                        sectionNode.Attributes[node.Key].Value = node.Value;
                        //Trace
                        context.Trace.Write("Update \""+node.Path+"\" value to \""+node.Value+"\"");
                        _changed = true;
                    }
                    else
                    {
                        //Trace
                        context.Trace.Warn("Configuration node \"" + node.Path + "\" not found. This setting would not be installed.");
                        continue;
                    }
                }

                if (action == ConfiguationUpdateActions.Add)
                {
                    XmlNode sectionNode = configDoc.SelectSingleNode(xpath);
                    XmlNode configNode = null;
                    if (!string.IsNullOrEmpty(node.Key))
                        configNode = configDoc.SelectSingleNode(xpath + "/" + node.Name + "[@" + node.Key + "='" + node.Value + "']");

                    var newNode = configDoc.CreateElement(node.Name);
                    var attr = configDoc.CreateAttribute(node.Key);
                    attr.Value = node.Value;
                    newNode.Attributes.Append(attr);
                    if (sectionNode != null)
                    {
                        sectionNode.AppendChild(newNode);
                        context.Trace.Write("Adding configuration node \"" + newNode.OuterXml + "\" to your web.config");
                        _changed = true;
                    }
                    else
                    {
                        context.Trace.Write("Configuration node not found.\"" + xpath + "\"");
                    }
                }
            }

            if (_changed)
                configDoc.Save(configPath);
        }
    }
}
